﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using NHibernate.Validator.Constraints;

namespace DataStore.Domain
{
    /// <summary>
    /// The base type of the catalog items.
    /// </summary>
    [Serializable]
    public class CatalogItem : IDataErrorInfo
    {
        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id.</value>
        public virtual Guid Id { get; set; }

        /// <summary>
        /// Gets or sets the document type.
        /// </summary>
        /// <value>The type.</value>
        public virtual DocumentType Type { get; set; }

        /// <summary>
        /// The name(s) of the author(s).
        /// </summary>
        /// <value>The author.</value>
        public virtual ICollection<Author> Authors { get; set; }

        /// <summary>
        /// Name(s) of editor(s). If there is also an author field, then the editor field gives 
        /// the editor of the book or collection in which the reference appears.
        /// </summary>
        /// <value>The editor.</value>
        public virtual ICollection<Editor> Editors { get; set; }

        /// <summary>
        /// A chapter (or section or whatever) number.
        /// </summary>
        /// <value>The chapter.</value>
        public virtual string Chapter { get; set; }

        /// <summary>
        /// The edition of a book - for example, "Second". 
        /// This should be an ordinal, and should have the first letter capitalized, as shown here; 
        /// the standard styles convert to lower case when necessary.
        /// </summary>
        /// <value>The edition.</value>
        public virtual string Edition { get; set; }

        /// <summary>
        /// How something strange has been published. The first word should be capitalized.
        /// </summary>
        /// <value>The how published.</value>
        public virtual string HowPublished { get; set; }

        /// <summary>
        /// The sponsoring institution of a technical report.
        /// </summary>
        /// <value>The institution.</value>
        public virtual ICollection<Company> Sponsors { get; set; }

        /// <summary>
        /// Gets or sets the date written.
        /// </summary>
        /// <value>The date written.</value>
        public virtual DateTime? DateWritten { get; set; }

        /// <summary>
        /// Gets or sets the date published.
        /// </summary>
        /// <value>The date published.</value>
        public virtual DateTime? DatePublished { get; set; }

        /// <summary>
        /// Gets or sets the comments.
        /// </summary>
        /// <value>The comments.</value>
        public virtual string Comment { get; set; }

        /// <summary>
        /// One or more page numbers or range of numbers.
        /// </summary>
        /// <value>The pages.</value>
        public virtual ICollection<Range> Pages { get; set; }

        /// <summary>
        /// The publisher's name.
        /// </summary>
        /// <value>The publisher.</value>
        public virtual Company Publisher { get; set; }

        /// <summary>
        /// The name of a series or set of books.
        /// </summary>
        /// <value>The series.</value>
        public virtual string Series { get; set; }

        /// <summary>
        /// The work's title.
        /// </summary>
        /// <value>The title.</value>
        [NotNullNotEmpty(Message = "Title cannot be empty")]
        public virtual string Title { get; set; }

        /// <summary>
        /// The type of a technical report - for example, "Research Note".
        /// </summary>
        /// <value>The type of the report.</value>
        public virtual string ReportType { get; set; }

        /// <summary>
        /// The volume of a journal or multi-volume book.
        /// </summary>
        /// <value>The volume.</value>
        public virtual string Volume { get; set; }

        /// <summary>
        /// Gets or sets the links of the document.
        /// </summary>
        /// <value>The link.</value>
        public virtual ICollection<Link> Links { get; set; }

        /// <summary>
        /// Gets or sets the country of publication.
        /// </summary>
        /// <value>The country.</value>
        public virtual Country Country { get; set; }

        /// <summary>
        /// Gets or sets the language of the document.
        /// </summary>
        /// <value>The language.</value>
        public virtual Language Language { get; set; }

        /// <summary>
        /// Gets or sets the width of the document.
        /// </summary>
        /// <value>The width.</value>
        [Min(0)]
        public virtual float? Width { get; set; }

        /// <summary>
        /// Gets or sets the height of the document.
        /// </summary>
        /// <value>The height.</value>
        [Min(0)]
        public virtual float? Height { get; set; }

        /// <summary>
        /// Gets or sets the cover.
        /// </summary>
        /// <value>The cover.</value>
        public virtual ICollection<Cover> Cover { get; set; }

        /// <summary>
        /// Gets or sets the number of pages.
        /// </summary>
        /// <value>The number of pages.</value>
        [Min(1)]
        public virtual int? NumberOfPages { get; set; }

        /// <summary>
        /// Gets or sets the publishing format of the document.
        /// </summary>
        /// <value>The format.</value>
        public virtual PublishingFormat Format { get; set; }

        /// <summary>
        /// Gets or sets the citations found in the document.
        /// </summary>
        /// <value>The citations.</value>
        public virtual ICollection<CatalogItem> Citations { get; set; }

        /// <summary>
        /// Gets or sets the keywords.
        /// </summary>
        /// <value>The keywords.</value>
        public virtual ICollection<Keyword> Keywords { get; set; }

        /// <summary>
        /// Gets or sets the categories.
        /// </summary>
        /// <value>The categories.</value>
        public virtual ICollection<Category> Categories { get; set; }

        /// <summary>
        /// Gets or sets the contents.
        /// </summary>
        /// <value>The contents.</value>
        public virtual string Contents { get; set; }

        /// <summary>
        /// Gets or sets the owner of the document.
        /// </summary>
        /// <value>The owner.</value>
        public virtual Person Owner { get; set; }

        /// <summary>
        /// Gets or sets the purchase date.
        /// </summary>
        /// <value>The purchase date.</value>
        public virtual DateTime? PurchaseDate { get; set; }

        /// <summary>
        /// Gets or sets the purchase store.
        /// </summary>
        /// <value>The purchase store.</value>
        public virtual Company PurchaseStore { get; set; }

        /// <summary>
        /// Gets or sets the purchase price.
        /// </summary>
        /// <value>The purchase price.</value>
        [Min(0)]
        public virtual float? PurchasePrice { get; set; }

        /// <summary>
        /// Gets or sets the current price.
        /// </summary>
        /// <value>The current price.</value>
        [Min(0)]
        public virtual float? CurrentPrice { get; set; }

        /// <summary>
        /// Gets or sets the condition.
        /// </summary>
        /// <value>The condition.</value>
        public virtual Condition Condition { get; set; }

        /// <summary>
        /// Gets or sets the rating.
        /// </summary>
        /// <value>The rating.</value>
        [Range(Min = 0, Max = 10)]
        public virtual int? Rating { get; set; }

        /// <summary>
        /// Gets or sets the dedication.
        /// </summary>
        /// <value>The dedication.</value>
        public virtual string Dedication { get; set; }

        /// <summary>
        /// Gets or sets the reading date.
        /// </summary>
        /// <value>The reading date.</value>
        public virtual DateTime? ReadingDate { get; set; }

        /// <summary>
        /// Gets or sets the borrower.
        /// </summary>
        /// <value>The borrower.</value>
        public virtual Person Borrower { get; set; }

        /// <summary>
        /// Gets or sets the borrow date.
        /// </summary>
        /// <value>The borrow date.</value>
        public virtual DateTime? BorrowDate { get; set; }

        /// <summary>
        /// Gets or sets the extras.
        /// </summary>
        /// <value>The extras.</value>
        public virtual ICollection<Extra> Extras { get; set; }

        /// <summary>
        /// Gets or sets the Library of Congress classification.
        /// </summary>
        /// <value>The lo C classification.</value>
        public virtual string LoCClassification { get; set; }

        /// <summary>
        /// Gets or sets the Dewey classification.
        /// </summary>
        /// <value>The dewey classification.</value>
        public virtual string DeweyClassification { get; set; }

        /// <summary>
        /// Gets or sets the other classification.
        /// </summary>
        /// <value>The other classification.</value>
        public virtual Classification OtherClassification { get; set; }

        /// <summary>
        /// Gets or sets the copyright.
        /// </summary>
        /// <value>The copyright.</value>
        public virtual string Copyright { get; set; }

        /// <summary>
        /// Gets or sets the quantity.
        /// </summary>
        /// <value>The quantity.</value>
        [Min(0)]
        public virtual int? Quantity { get; set; }

        /// <summary>
        /// Gets or sets the location of the document.
        /// </summary>
        /// <value>The location.</value>
        public virtual string Location { get; set; }


        #region IDataErrorInfo Members

        /// <summary>
        /// Gets an error message indicating what is wrong with this object.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// An error message indicating what is wrong with this object. The default is an empty string ("").
        /// </returns>
        public virtual string Error
        {
            get 
            {
                string error = string.Empty;

                foreach (string field in FieldsForValidation)
                {
                    if (this[field] != string.Empty)
                    {
                        error += this[field] + "\n";
                    }
                }

                return error;
            }
        }

        /// <summary>
        /// Gets the <see cref="System.String"/> with the specified column name.
        /// IDataErrorInfo implementation.
        /// </summary>
        /// <value></value>
        public virtual string this[string columnName]
        {
            get
            {
                string error = String.Empty;

                if (columnName == "Title")
                {
                    if (string.IsNullOrEmpty(Title))
                    {
                        error = "Title can't be empty";
                    }
                }

                if (columnName == "Quantity")
                {
                    if (Quantity.HasValue && Quantity <= 0)
                    {
                        error = "At least one must be available";
                    }
                }

                if (columnName == "Width")
                {
                    if (Width.HasValue)
                    {
                        if (Width <= 0.0f)
                        {
                            error = "Width must be greater then 0";
                        }
                    }
                }

                if (columnName == "Height")
                {
                    if (Height.HasValue)
                    {
                        if (Height <= 0.0f)
                        {
                            error = "Height must be greater then 0";
                        }
                    }
                }

                if (columnName == "NumberOfPages")
                {
                    Console.WriteLine(NumberOfPages);
                }

                return error;
            }
        }

        #endregion

        /// <summary>
        /// Fileds for validation
        /// </summary>
        protected List<string> FieldsForValidation = new List<string> { "Title", "Quantity", "Width", "Height", "NumberOfPages" };

        /// <summary>
        /// Checks if model is valid, contains valid data
        /// </summary>
        public virtual bool IsValid 
        { 
            get
            {
                foreach (string field in FieldsForValidation)
                {
                    if(this[field] != string.Empty)
                    {
                        return false;
                    }
                }

                return true;
            } 
        }
    }
}
